import pandas as pd
from pyecharts import options as opts
from pyecharts.charts import Boxplot, Bar, Scatter, Pie, Radar, HeatMap
from sqlalchemy import create_engine

def Mysql():
    """
    连接MySQL数据库并读取数据
    """
    username = 'root'
    password = '123456'
    host = 'localhost'
    port = '3306'
    database = 'jiudeshuju'
    # 创建连接引擎
    engine = create_engine(f'mysql+pymysql://{username}:{password}@{host}:{port}/{database}')
    sql_query = "SELECT * FROM qingxideshuju"
    # 使用 pandas 读取 SQL 查询结果
    data = pd.read_sql(sql_query, engine)
    return data

def BoxDiagram():
    """
    生成箱型图，显示不同品牌的酒的价格分布
    """
    data = Mysql()
    print(data)
    # 将价格列转换为浮点数，并处理无法转换的情况
    data['价格'] = data['价格'].astype(float)
    data['价格'] = pd.to_numeric(data['价格'], errors='coerce')
    data = data.dropna(subset=['价格'])
    # 按品牌分组，计算每个品牌的平均价格
    grouped = data.groupby('品牌')['价格'].apply(list).reset_index()
    grouped['平均价格'] = grouped['价格'].apply(lambda x: sum(x) / len(x))
    # 按平均价格排序，取前40个品牌
    grouped = grouped.sort_values(by='平均价格', ascending=False).head(40)
    # 过滤掉价格列表长度小于5的品牌
    grouped = grouped[grouped['价格'].apply(len) > 4]
    print(grouped)
    # 创建箱型图
    boxplot = Boxplot().add_xaxis(grouped['品牌'].tolist())
    boxplot.add_yaxis("价格分布", boxplot.prepare_data(grouped['价格'].tolist()))
    boxplot.set_global_opts(
        title_opts=opts.TitleOpts(title="价格区间与品牌分布"),
        yaxis_opts=opts.AxisOpts(name="价格 (¥)"),
        xaxis_opts=opts.AxisOpts(name="品牌"),
        datazoom_opts=[opts.DataZoomOpts(type_="slider", xaxis_index=0, range_start=0, range_end=100)]
    )
    boxplot.render_notebook()
    boxplot.render("./箱型图.html")

def is_beer(title):
    """
    检查标题中是否包含“啤酒”、“红酒”或“白酒”
    """
    if "啤酒" in title:
        return "啤酒"
    elif "红酒" in title:
        return '红酒'
    else:
        return '白酒'

def zhuzhangtu():
    """
    生成柱状图，显示不同类型的酒的评价数
    """
    data = Mysql()
    data['评价数'] = data['评价数'].astype(int)
    # 识别酒的类型
    data['类型'] = data['标题'].apply(is_beer)
    # 按类型分组，计算总评价数
    head = data.groupby('类型')[['评价数']].sum().sort_values('评价数', ascending=False)
    print(head)
    print(head.index.tolist())
    # 创建柱状图
    bar = (
        Bar()
        .add_xaxis(head.index.tolist())
        .add_yaxis("评价数", head['评价数'].tolist())
        .set_global_opts(
            title_opts=opts.TitleOpts(title="评价数与商品类型的关系"),
            yaxis_opts=opts.AxisOpts(name="评价数"),
            xaxis_opts=opts.AxisOpts(name="商品类型")
        )
    )
    bar.render_notebook()
    bar.render("./柱状图.html")

def changdi():
    """
    生成散点图，显示不同酒精度的出现次数
    """
    data = Mysql()
    # 按酒精度分组，计算出现次数
    size = data.groupby('酒精度').size().reset_index(name='出现次数').sort_values('出现次数', ascending=False).head(10)
    print(size)
    size['酒精度'] = size['酒精度'].astype('str')
    size['出现次数'] = size['出现次数'].astype(int)
    # 创建散点图
    scatter = (
        Scatter()
        .add_xaxis(size['酒精度'].tolist())
        .add_yaxis("酒精度", size['出现次数'].tolist())
        .set_global_opts(
            title_opts=opts.TitleOpts(title="酒精度出现的次数的关联"),
            xaxis_opts=opts.AxisOpts(name="酒精度"),
            yaxis_opts=opts.AxisOpts(name="出现次数")
        )
    )
    # 渲染图表
    scatter.render_notebook()
    scatter.render('F:\比赛\毕业设计\别人的2\宋恋\散点图.html')

def bintu():
    """
    生成玫瑰图，显示不同产地的评价数
    """
    data = Mysql()
    # 处理产地列，提取中国以外的部分
    data['产地'] = data['产地'].apply(
        lambda x: str(x).split('中国')[1] if '中国' in str(x) and len(str(x).split('中国')) > 1 else x)
    data['产地'] = data['产地'].replace('  ', '不知道产地')
    data['评价数'] = data['评价数'].astype(int)
    # 按产地和品牌分组，计算总评价数
    grouped = data.groupby(['产地', '品牌']).agg({'评价数': 'sum'}).reset_index()
    # 按总评价数排序，取前20个产地
    total_reviews = grouped.groupby('产地')['评价数'].sum().reset_index().sort_values('评价数', ascending=False).head(20)
    data_pair = [list(z) for z in zip(total_reviews['产地'], total_reviews['评价数'])]
    print(data_pair)
    # 创建玫瑰图
    c = Pie().add(
        '热度为',
        data_pair,
        radius=['30%', '75%'],
        center=['50%', '50%'],
        rosetype='area',
        label_opts=opts.LabelOpts(is_show=True, position='right', formatter="{b}: {c} ({d}%)", font_size=10)
    ).set_global_opts(
        title_opts=opts.TitleOpts(title="玫瑰图"),
        legend_opts=opts.LegendOpts(
            orient="vertical",
            pos_right="-10%",
            pos_top="20%",
            textstyle_opts=opts.TextStyleOpts(font_size=10)
        )
    )
    c.render_notebook()
    c.render("./玫瑰图.html")

def fenzutiaoxing():
    """
    生成分组条形图，显示不同储存方法与白酒香型的关联
    """
    data = Mysql()
    # 将储存方法列拆分为多个值
    data['储存方法'] = data['储存方法'].str.split(',')
    data['白酒香型'] = data['白酒香型'].replace('  ', '未知').replace('NoN', '未知')
    df = data.explode('储存方法')
    # 按白酒香型和储存方法分组，计算出现次数
    storage_counts = df.groupby(['白酒香型', '储存方法']).size().unstack(fill_value=0)
    print(storage_counts)
    bar = Bar()
    for col in storage_counts.columns:
        bar.add_yaxis(col, storage_counts[col].tolist(), label_opts=opts.LabelOpts(position="top"))
    bar.add_xaxis(storage_counts.index.tolist())
    bar.set_global_opts(
        title_opts=opts.TitleOpts(title="储存方法与商品类型的关联"),
        xaxis_opts=opts.AxisOpts(name="商品类型"),
        yaxis_opts=opts.AxisOpts(name="数量"),
        legend_opts=opts.LegendOpts(pos_left="right", textstyle_opts=opts.TextStyleOpts(font_size=10)),
        datazoom_opts=[opts.DataZoomOpts(type_="slider", xaxis_index=0, range_start=0, range_end=30)]
    )
    bar.render_notebook()
    bar.render("./分组条行图.html")

def liedatu():
    """
    生成雷达图，显示综合评分最高的前4个商品
    """
    data = Mysql()
    data['价格'] = data['价格'].astype(float)
    # 计算综合评分
    data['综合评分'] = (data['价格'] + data['评价数'] + data['单支容量']) / 3
    sorted_data = data.sort_values(by='综合评分', ascending=False)
    top_3 = sorted_data.head(4)
    print(top_3)
    data_values = top_3[['价格', '评价数', '单支容量']].values.tolist()
    print(data_values)
    # 创建雷达图
    radar = (
        Radar()
        .add_schema(
            schema=[
                opts.RadarIndicatorItem(name="价格", max_=100000),
                opts.RadarIndicatorItem(name="评价数", max_=90000),
                opts.RadarIndicatorItem(name="单支容量", max_=800),
            ]
        ).add("商品", data_values, label_opts=opts.LabelOpts(is_show=False))
        .set_series_opts(tooltip_opts=opts.TooltipOpts(is_show=True))
        .set_global_opts(title_opts=opts.TitleOpts(title="容量、价格与评价的综合考量"))
    )
    # 渲染图表
    radar.render_notebook()
    radar.render("./雷达图.html")

if __name__ == '__main__':
    # 生成箱型图
    BoxDiagram()
    # 生成柱状图
    zhuzhangtu()
    # 生成散点图
    changdi()
    # 生成玫瑰图
    bintu()
    # 生成分组条形图
    fenzutiaoxing()
    # 生成雷达图
    liedatu()